#include"primitive.cpp"

namespace Environment
{
	GLfloat g=0;
};

class Object
{
protected:
	Affine transformation;
	Vector3D velocity;
	Point3D center;
	GLfloat mass;
	GLfloat density;
public:
	Object()
	{
		density = 7000;
	}
	Object(Point3D c, Vector3D vel)
	{
		center = c;
		translate(Vector3D(c.x,c.y,c.z));
		//transformation.print_affine();
		velocity = vel;
		density = 7000;
	}
	GLfloat get_mass()
	{
		return mass;
	}
	void set_center(Point3D c)
	{
		velocity.y*=0.8;
		translate(c-center);
		center = c;
	}
	void set_center_y_z(GLfloat y,GLfloat z)
	{
		translate(Point3D(center.x,y,z)-center);
		center = Point3D(center.x,y,z);
	}
	Point3D get_center()
	{
		return center;
	}
	void set_velocity(Vector3D new_velocity)
	{
		velocity = new_velocity;
	}
	Vector3D get_velocity()
	{
		return velocity;
	}
	void rotate(GLfloat theta, Vector3D axis)
	{
		transformation.rotate(theta,axis);
	}
	void translate(Vector3D translate_vector)
	{
		transformation.translate(translate_vector);
	}
	void scale(GLfloat sx, GLfloat sy, GLfloat sz)
	{
		transformation.scale(sx, sy, sz);
	}
	void move(GLfloat time_diff)
	{
		//cout<<velocity.x<<" "<<velocity.y<<" "<<velocity.z<<"\n";
		Vector3D displacement = velocity * time_diff + Vector3D(0,-1,0)*0.5*(Environment::g)*time_diff*time_diff;
		//transformation.print_affine();
		translate(displacement);
		center = center + displacement;
		//cout<<center.z<<"\namespace";
		velocity = velocity + Vector3D(0,-1,0)*Environment::g*time_diff;
	}
	void print_center()
	{
		cout<<center.x<<" : "<<center.y<<" : "<<center.z<<"\n";
	}
};
class Slab : public Object
{
	GLfloat length,width,height;
public:
	Slab(Point3D c,Vector3D v) : Object (c,v)
	{
		length=0.1;
		width=1;
		height=1;
		transformation.scale(length,width,height);
	}
	void draw()
	{
		//transformation.print_affine();
		transformation.apply_transformation();
		glutSolidCube(2);
	}
	void operator=(Slab s)
	{
		length=s.length;
		width=s.width;
		height=s.height;
		velocity = s.velocity;
		center = s.center;
		transformation = s.transformation;
		mass = s.mass;
	}

};
class Sphere : public Object
{
	GLfloat radius;	
public:
	Sphere() : Object()
	{
		radius = 0.2;
		mass = density * 4/3 * 3.14 * radius*radius*radius;

	}
	Sphere(Point3D c, GLfloat r, Vector3D init_vel) : Object(c,init_vel)
	{
		radius = r;
		mass = density * 4/3 * 3.14 * radius*radius*radius;
	}
	GLfloat get_radius()
	{
		return radius;
	}
	void draw()
	{
		transformation.apply_transformation();
		glutSolidSphere(radius,15,15);
	}
	void operator=(Sphere s)
	{
		radius = s.radius;
		velocity = s.velocity;
		center = s.center;
		transformation = s.transformation;
		mass = s.mass;
	}
};

class Wall
{
public:
	GLfloat a,b,c,d; // co-efficients
	Wall()
	{
		a = b = c = d = 0;
	}
	Wall(Point3D p1, Point3D p2, Point3D p3)
	{

		a = (p2.y-p1.y)*(p3.z-p1.z) - (p3.y-p1.y)*(p2.z-p1.z);
		b = (p2.z-p1.z)*(p3.x-p1.x) - (p3.z-p1.z)*(p2.x-p1.x);
		c = (p2.x-p1.x)*(p3.y-p1.y) - (p3.x-p1.x)*(p2.y-p1.y);
		d = -(a*p1.x + b*p1.y + c*p1.z);

	}
	void operator=(Wall w)
	{
		a=w.a;
		b=w.b;
		c=w.c;
		d=w.d;
	}
};

class World
{
private:
	void get_spheres_from_file()
	{
		Point3D center;
		Vector3D velocity;
		GLfloat radius;
		FILE *f = fopen("spheres.txt","r");
		fscanf(f,"%d\n",&no_spheres);
		spheres = (Sphere *) malloc(sizeof(Sphere)*no_spheres);
		for(int i=0; i<no_spheres; i++){
			fscanf(f,"(%f,%f,%f),%f,(%f,%f,%f)\n",&(center.x),&(center.y),&(center.z),&radius,&(velocity.x),&(velocity.y),&(velocity.z));
			Sphere s(center,radius,velocity);
			spheres[i]=s;
		}
		fclose(f);
	}	
	void get_walls_from_file()
	{
		Point3D p1,p2,p3;

		FILE *f = fopen("walls.txt","r");
		fscanf(f,"%d\n",&no_walls);
		walls = (Wall *) malloc(sizeof(Wall)*no_walls);
		for(int i=0; i<no_walls; i++){
			fscanf(f,"(%f,%f,%f),(%f,%f,%f),(%f,%f,%f)\n",&(p1.x),&(p1.y),&(p1.z),
														  &(p2.x),&(p2.y),&(p2.z),
														  &(p3.x),&(p3.y),&(p3.z));
			Wall w(p1,p2,p3);
			walls[i]=w;
		}
		fclose(f);
	}
public:
	Wall *walls;
	GLint no_walls;
	Sphere *spheres;
	GLint no_spheres;
	World()
	{
		no_spheres = 0;
		no_walls = 0;
	}
	void get_world_from_file()
	{
		get_spheres_from_file();
		get_walls_from_file();
	}
	~World()
	{
		free(walls);
		free(spheres);
	}
};

World *w_pointer;
Slab *player, *opponent;